import 'package:sinosheets/utils/common_utils/log_util.dart';

typedef void EventCallback(arg);

class EventBus {
  //私有构造函数
  EventBus._internal();

  //保持单例
  static EventBus _singleton = EventBus._internal();

  //工厂构造函数
  factory EventBus() => _singleton;

  //保存事件订阅者队列，key: 事件名成 value:对应的事件订阅者队列
  final _emap = Map<Object, List<EventCallback>>();

  //添加订阅者
  void on(eventName, EventCallback f) {
    _emap[eventName] ??= <EventCallback>[];
    _emap[eventName]?.add(f);
  }

  //移除订阅者
  void off(eventName, [EventCallback? f]) {
    var list = _emap[eventName];
    if (eventName == null || list == null) {
      return;
    }
    if (f == null) {
      _emap[eventName] = [];
    } else {
      list.remove(f);
    }
  }

  //触发事件，事件触发后该事件所有订阅者会被调用
  void emit(eventName, [arg]) {
    var list = _emap[eventName];
    if (list == null) return;
    int len = list.length - 1;
    //反向遍历，防止订阅者在回调中移除自身带来的下标错位
    for (var i = len; i > -1; --i) {
      list[i](arg);
    }
  }
}

/// 定义一个top-level(全局)变量，页面A中订阅者会被调用
var bus = EventBus();

/// 消息的类型
enum BusType {
  userInfoRefresh(name: "userInfoRefresh"),
  login(name: "login"),
  logout(name: "logout"),
  badgeRefresh(name: "badgeRefresh");

  const BusType({required this.name});

  final String name;
}

extension BusTypeMethods on BusType {
  String get label {
    switch (this) {
      case BusType.userInfoRefresh:
        return "个人信息更新";
      case BusType.login:
        return "登录";
      case BusType.logout:
        return "退出登录";
      case BusType.badgeRefresh:
        return "小红点数量更新";
    }
  }

  /// 添加响应函数
  void on(void Function(dynamic arg) action) {
    bus.on(name, (arg) {
      action(arg);
      LogUtil.e("执行($label)的事件的响应函数($action)");
      if (arg != null) {
        LogUtil.e("收到参数: $arg");
      }
    });
    LogUtil.e("添加了($label)的监听");
  }

  /// 移除
  void off() {
    bus.off(name);
    LogUtil.e("移除了($label)的监听");
  }

  /// 触发事件
  void emit([arg]) {
    bus.off(name, arg);
    LogUtil.e("触发了($label)的事件");
    if (arg != null) {
      LogUtil.e("携带参数: $arg");
    }
  }
}
